/*
 *  ckr_spec_macros.h
 *  ckrSpec
 *
 *  Created by C. Keith Ray on 2006.11.03.
 *  Copyright 2006 __MyCompanyName__. All rights reserved.
 *
 */

#pragma once


#define VALUE(x)							AssertableValue<typeof(x)>( (x), #x, *this, __LINE__, __FILE__ )

#define CSTRING_VALUE(x)				AssertableValueCString( (x), #x, *this, __LINE__, __FILE__ )

#define POINTER(x)						AssertablePointer( (x), #x, *this, __LINE__, __FILE__ )


#define FAIL(x)							fail_impl( (x), __LINE__, __FILE__ )


#define SHOULD_BE_TRUE					should_be_true()
#define SHOULD_BE_FALSE					should_be_false()

#define SHOULD_EQUAL(x)					should_equal_impl( (x), #x )

#define SHOULD_NOT_EQUAL(x)			should_not_equal_impl( (x), #x )

#define SHOULD_BE_LESS_THAN(x)		should_be_less_than_impl( (x), #x )

#define SHOULD_BE_GREATER_THAN(x)	should_be_greater_than_impl( (x), #x )

#define SHOULD_BE_LESS_THAN_OR_EQUAL_TO(x)  should_be_less_than_or_equal_to_impl( (x), #x )

#define SHOULD_BE_GREATER_THAN_OR_EQUAL_TO(x)  should_be_greater_than_or_equal_to_impl( (x), #x )

#define SHOULD_BE_BETWEEN(x,y)		should_be_between_impl( (x), #x, (y), #y )

#define SHOULD_BE_CLOSE_TO(x,dx)		should_be_close_to_impl( (x), #x, (dx), #dx )

#define SHOULD_NOT_BE_BETWEEN(x,y)	should_not_be_between_impl( (x), #x, (y), #y )

#define SHOULD_NOT_BE_CLOSE_TO(x,dx)	should_not_be_close_to_impl( (x), #x, (dx), #dx )

#define SHOULD_BE_WITHIN(x,y)			should_be_within_impl( (x), #x, (y), #y )

#define SHOULD_NOT_BE_WITHIN(x,y)	should_not_be_within_impl( (x), #x, (y), #y )

#define SHOULD_BE_NULL					should_be_null_impl()

#define SHOULD_NOT_BE_NULL				should_not_be_null_impl()

#define THIS_CODE							try{

#define SHOULD_THROW(x)					FAIL("code throwing '" #x "'"); } catch ( x& ex ) { }

#define SHOULD_NOT_THROW				} catch ( std::exception& ex ) \
													{ fail_not_throw_impl( ex, __LINE__, __FILE__ ); }


#define CONTAINER(x)						AssertableContainer<typeof(x)>( (x), #x, *this, __LINE__, __FILE__ )

#define SHOULD_CONTAIN(y)				should_contain_impl( (y), #y )

#define SHOULD_NOT_CONTAIN(y)			should_not_contain_impl( (y), #y )


#define DECLARE_SPEC(specName)										\
class specName : public ckr::Context								\
{																				\
public:																		\
	specName()																\
		: Context( #specName, __LINE__, __FILE__ )				\
	{ };																		\
	virtual void spec();													\
}

#define IMPLEMENT_SPEC_WITH_RUNNER(specName,runner)			\
	static specName staticInstance##specName;						\
	static RegisterContextWithRunner register##specName(		\
		& staticInstance##specName, runner);						\
	void specName::spec()

#define IMPLEMENT_SPEC(specName)										\
	IMPLEMENT_SPEC_WITH_RUNNER(specName,SpecRunner::getGlobalSpecRunner())
	
#define BEGIN_CONTEXT(specName)										\
	class specName : public ckr::Context							\
	{																			\
	public:																	\
		explicit specName( const char * subName)					\
			: Context( subName, __LINE__, __FILE__ )				\
		{ };

#define END_CONTEXT		}

#define SPECIFY_WITH_RUNNER(baseSpecName,specName,runner)	\
class specName : public baseSpecName								\
	{																			\
	public:																	\
		specName()															\
			: baseSpecName( #specName )								\
		{ };																	\
		virtual void spec();												\
	};																			\
	static specName staticInstance##specName;						\
	static RegisterContextWithRunner register##specName(		\
			& staticInstance##specName, runner);					\
	void specName::spec()

#define SPECIFY(baseSpecName,specName)								\
	SPECIFY_WITH_RUNNER(baseSpecName,specName,					\
		SpecRunner::getGlobalSpecRunner())

#define SPECIFY_(specName)												\
class specName : public Context										\
	{																			\
	public:																	\
		specName()															\
			: Context( #specName,__LINE__,__FILE__ )				\
		{ };																	\
		virtual void spec();												\
	};																			\
	static specName staticInstance##specName;						\
	static RegisterContextWithRunner register##specName(		\
			& staticInstance##specName,								\
			SpecRunner::getGlobalSpecRunner() );					\
	void specName::spec()

